package com.lsu.app.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.lsu.app.bean.*;
import com.lsu.app.config.target.RequestRoles;
import com.lsu.app.service.*;
import com.lsu.app.tool.AESUtil;
import com.lsu.app.tool.R;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author hjj
 * @date 2023/11/8 10:39
 */
@RestController
@Slf4j
@CrossOrigin
@RequestMapping("/detes")
public class scheduleController { //课程表控制类
    @Autowired
    private HttpServletRequest request;
    private final ScheduleService scheduleService;
    private final LogService logService;
    private final TimeTableService timeService;
    private final ScheduleCourseService scheduleCourseService;
    private final CourseService courseService;
    private final ResourceService resourceService;
    private final KindService kindService;
    private final UserService userService;
    public scheduleController(ScheduleService scheduleService, LogService logService, TimeTableService timeService,
                              ScheduleCourseService scheduleCourseService, CourseService courseService, ResourceService resourceService, KindService kindService, UserService userService) {
        this.scheduleService = scheduleService;
        this.logService = logService;
        this.timeService = timeService;
        this.scheduleCourseService = scheduleCourseService;
        this.courseService = courseService;
        this.resourceService = resourceService;
        this.kindService = kindService;
        this.userService = userService;
    }

    @RequestRoles({"student","teacher"})
    @PostMapping("/createSchedule")
    @ApiOperation("a创建课程表")
    public R<Schedule> createSchedule(
            @ApiParam("课程表名称")@RequestParam("name") String name,
            @ApiParam("开课日期(yyyy-MM-dd)")@RequestParam("date") String date,
            @ApiParam("总周次")@RequestParam("weekly") Integer weekly,
            @ApiParam("简介")@RequestParam(value = "remake",required = false) String remake,
            @ApiParam("是否公开(1公开，0私有)")@RequestParam("isPublic") Integer isPublic,
            @ApiParam("是否当前使用(1使用，0不启用)")@RequestParam("state") Integer state
    ){
        Integer userId = (Integer) request.getSession().getAttribute("id");
        if(scheduleService.existNameOfSch(userId,name)){
            return R.err("自己课程列表中已存在该课程表名，请修改新课程表名");
        }
        try{
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            sdf.parse(date);
        }catch (ParseException e){
            return R.err("日期格式错误");
        }
        if(state==1){
            scheduleService.update(new LambdaUpdateWrapper<Schedule>().eq(Schedule::getUserId,userId).set(Schedule::getState,0));
        }
        //存入课程表
        Schedule schedule = new Schedule(remake,userId,name, LocalDateTime.now().toString(),date,weekly,5,state,isPublic);
        scheduleService.save(schedule);
        //设置默认课程节数以及时间
        String[] startTime = {"08:00:00","9:45:00","14:00:00","15:45:00","18:40:00"};
        String[] endTime = {"9:30:00","12:15:00","15:30:00","17:15:00","20:10:00"};
        for(int i=0;i<5;i++){
            TimeTable timeTable = new TimeTable(schedule.getId(),i+1,endTime[i],startTime[i]);
            timeService.save(timeTable);
        }
        //创建默认空课程 课程id为0
        for(int i=1;i<=7;i++){
            for (int j=1;j<=5;j++){
                scheduleCourseService.save(new ScheduleCourse(schedule.getId(),i,j,0,weekly));
            }
        }
        logService.createLog("SCHEDULE_CREATE","schedule-"+name,"create-"+request.getSession().getAttribute("username"));
        return R.success(scheduleService.getById(schedule.getId()));
    }
    @RequestRoles({"student","teacher"})
    @PutMapping("/putSchCourse")
    @ApiOperation("c设置课程表中的课程属性")
    public R<ScheduleCourse> putSchCourse(
            @ApiParam("课表中的课程位置id")@RequestParam("scheduleCourseId") Integer scheduleCourseId,
            @ApiParam("课程开始周次")@RequestParam("startWeekly") Integer startWeekly,
            @ApiParam("课程结束周次")@RequestParam("endWeekly") Integer endWeekly,
            @ApiParam("备注")@RequestParam("remake") String remake,
            @ApiParam("1单周，2双周等")@RequestParam("skip") Integer skip,
            @ApiParam("课程id")@RequestParam("courseId") Integer courseId
    ){
        if(scheduleCourseService.getById(scheduleCourseId)==null||courseService.getById(courseId)==null){
            return R.err("课程表或课程不存在");
        }
        scheduleCourseService.update(new LambdaUpdateWrapper<ScheduleCourse>().eq(ScheduleCourse::getId,scheduleCourseId)
                .set(ScheduleCourse::getStartWeekly,startWeekly)
                .set(ScheduleCourse::getEndWeekly,endWeekly)
                .set(ScheduleCourse::getRemake,remake)
                .set(ScheduleCourse::getSkip,skip)
                .set(ScheduleCourse::getCourseId,courseId)
                .set(ScheduleCourse::getState,1));
        ScheduleCourse scheduleCourse = scheduleCourseService.getById(scheduleCourseId);
        Schedule schedule = scheduleService.getById(scheduleCourse.getScheduleId());
        Integer culWeek = AESUtil.getCulWeekly(schedule.getStartDate(),schedule.getWeekly(),schedule.getState());
        if(scheduleCourse.getState()==1){//进行是否在 周次中存在课程
            if(culWeek>=scheduleCourse.getStartWeekly()&&culWeek<=scheduleCourse.getEndWeekly()&&culWeek%scheduleCourse.getSkip()==0){
                //在时间范围内，并且满足单双周
                scheduleCourse.setState(1);
            }else{
                //不满足单双周或不在本周内，则为非本周课程
                scheduleCourse.setState(2);
            }
            scheduleCourse.setCourseName(courseService.getCourseNameById(scheduleCourse.getCourseId()));
            scheduleCourse.setCourseTeacherName(courseService.getTeacherNameByCourseId(scheduleCourse.getCourseId()));
        }
        return R.success(scheduleCourse);
    }
    @RequestRoles({"student","teacher"})
    @PostMapping("/produceSchedule")
    @ApiOperation("$通过提交课程id集合，智能创建课程表")
    public R<ReturnSchedule> produceSchedule(
            @ApiParam("课程表id")@RequestParam("scheduleId") Integer scheduleId,
            @RequestBody List<Integer> courseIds
    ){
        if(courseIds.size()==0){
            return R.err("课程集合不能为空");
        }
        Schedule schedule = scheduleService.getById(scheduleId);
        if(schedule==null){
            return R.err("课程表不存在");
        }
        //使用遗传算法
        Map<Integer,String[]> maps = new HashMap<>();
        for (Integer id : courseIds) {
            maps.put(id,kindService.getValueByCourseId(id));
        }
        int[][] sets = AESUtil.geneticAlgorithm(maps,courseIds);
        for (int i=0;i<sets.length;i++){
            for (int j=0;j<sets[i].length;j++){
                LambdaUpdateWrapper<ScheduleCourse> wrapper = new LambdaUpdateWrapper<>();
                wrapper.eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,i+1).eq(ScheduleCourse::getWhichNum,j+1)
                        .set(ScheduleCourse::getCourseId,sets[i][j]);
                if(sets[i][j]!=0){
                    wrapper.set(ScheduleCourse::getState,1);
                }
                scheduleCourseService.update(wrapper);
            }
        }
        return getSchedule(schedule.getId());
    }
    @RequestRoles({"student"})
    @PutMapping("/putState")
    @ApiOperation("a修改课程表状态为[使用当前课表]")
    public R<String> putState(
        @ApiParam("课表id")@RequestParam("scheduleId") Integer scheduleId
    ){
        Integer userId = (Integer) request.getSession().getAttribute("id");
        //先将所有数据改为0状态
        scheduleService.update(new LambdaUpdateWrapper<Schedule>().eq(Schedule::getUserId,userId).set(Schedule::getState,0));
        scheduleService.update(new LambdaUpdateWrapper<Schedule>().eq(Schedule::getId,scheduleId).set(Schedule::getState,1));
        return R.success("修改成功");
    }
    @RequestRoles({"student","teacher"})
    @PutMapping("/putSchedule")
    @ApiOperation("a修改课程表简要信息")
    public R<ReturnSchedule> putSchedule(
            @ApiParam("课表id")@RequestParam("scheduleId") Integer scheduleId,
            @ApiParam("课程表名称")@RequestParam("name") String name,
            @ApiParam("开课日期(yyyy-MM-dd)")@RequestParam("startDate") String startDate,
            @ApiParam("总周次")@RequestParam("weekly") Integer weekly,
            @ApiParam("是否公开(1公开，0私有)")@RequestParam("isPublic") Integer isPublic
    ){
        Integer userId = (Integer) request.getSession().getAttribute("id");
        if(scheduleService.getById(scheduleId).getUserId()!=userId){
            return R.err("无权限修改");
        }
        if(scheduleService.existNameOfSch(userId,name)){
            return R.err("自己课程列表中已存在该课程表名，请修改新课程表名");
        }
        LambdaUpdateWrapper<Schedule> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Schedule::getId,scheduleId)
                .set(Schedule::getName,name)
                .set(Schedule::getStartDate,startDate)
                .set(Schedule::getWeekly,weekly)
                .set(Schedule::getIsPublic,isPublic)
                .set(Schedule::getUpdateTime,LocalDateTime.now());
        if(scheduleService.update(wrapper)){
            return getSchedule(scheduleId);
        }else {
            return R.err("更新失败，稍后再试");
        }
    }
    @RequestRoles({"student","teacher"})
    @DeleteMapping("/delSchedule")
    @ApiOperation("a删除课程表信息")
    public R<String> deleteSchedule(
        @ApiParam("课表id")@RequestParam("scheduleId") Integer scheduleId
    ){
        scheduleService.removeById(scheduleId);
        scheduleCourseService.remove(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId));
        timeService.remove(new LambdaQueryWrapper<TimeTable>().eq(TimeTable::getScheduleId,scheduleId));
        return R.success("删除成功");
    }

    @RequestRoles({"student","teacher"})
    @GetMapping("/list")
    @ApiOperation("a获取我的所有课程表列表")
    public R<List<Schedule>> getAllSchedule(){
        Integer userId = (Integer) request.getSession().getAttribute("id");
        List<Schedule> list = scheduleService.list(new LambdaQueryWrapper<Schedule>().eq(Schedule::getUserId,userId));
        for (Schedule schedule : list) {
            schedule.setUserNicName(userService.getNameById(schedule.getUserId()));
            schedule.setUserImg(resourceService.getHeadUrlByUorrIdAndType(schedule.getUserId()));
        }
        return R.success(list);
    }

    @RequestRoles({"student","teacher"})
    @GetMapping("/listPublic")
    @ApiOperation("a所有公开课程表列表")
    public R<List<Schedule>> getAllScheduleInPublic(){
        List<Schedule> list = scheduleService.list(new LambdaQueryWrapper<Schedule>().eq(Schedule::getIsPublic,1));
        for (Schedule schedule : list) {
            schedule.setUserNicName(userService.getNameById(schedule.getUserId()));
            schedule.setUserImg(resourceService.getHeadUrlByUorrIdAndType(schedule.getUserId()));
        }
        return R.success(list);
    }



    @RequestRoles({"student","teacher"})
    @PostMapping("/addPublic")
    @ApiOperation("a添加公开课程表中的课程表")
    public R<String> addScheduleInPublic(
        @ApiParam("课表id")@RequestParam("scheduleId") Integer scheduleId,
        @ApiParam("课程表名称")@RequestParam("newName") String newName
    ){
        Integer userId = (Integer) request.getSession().getAttribute("id");
        if(scheduleService.existNameOfSch(userId,newName)){
            return R.err("自己课程列表中已存在该课程表名，请修改新课程表名");
        }
        Schedule schedule = scheduleService.getById(scheduleId);
        if(schedule.getIsPublic()==0){
            return R.err("非公开课程表");
        }
        Schedule newSchedule = new Schedule(schedule.getRemake(), userId,newName,LocalDateTime.now().toString(),schedule.getStartDate(),
                schedule.getWeekly(),schedule.getPitchNum(),0,1);
        //添加课程表
        scheduleService.save(newSchedule);
        //添加课表与课的关联
        scheduleCourseService.getScs(scheduleId,newSchedule.getId());
        //添加课程时间关联
        timeService.copySc(scheduleId,newSchedule.getId());
        return R.success("添加成功");
    }


    @RequestRoles({"student","teacher"})
    @GetMapping("/getTime")
    @ApiOperation("b获取课程节数&时间")
    public R<List<TimeTable>> getTime(
        @ApiParam("课表id")@RequestParam("scheduleId") Integer scheduleId
    ){
        return R.success(timeService.list(new LambdaQueryWrapper<TimeTable>().eq(TimeTable::getScheduleId,scheduleId)));
    }
    @RequestRoles({"student","teacher"})
    @PutMapping("/putTime")
    @ApiOperation("b修改课程节数&时间")
    public R<String> putTime(
        @ApiParam("课表id")@RequestParam("scheduleId") Integer scheduleId,
        @ApiParam("课表时间集[间接改变课程节数]")@RequestBody List<TimeTable> timeTables
    ){
        Schedule schedule = scheduleService.getById(scheduleId);
        if(schedule.getUserId()!=request.getSession().getAttribute("id")){
            return R.err("无权修改");
        }
        Integer num  = schedule.getPitchNum();
        if(num>timeTables.size()){//每日总课程变小
                //删去多余的课程
                for (int j=timeTables.size()+1;j<=num;j++){
                    scheduleCourseService.remove(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId)
                            .eq(ScheduleCourse::getWhichNum,j));
                }
        }else if(num<timeTables.size()){
                //添加课程
                for (int i=num+1;i<=timeTables.size();i++){
                    for (int j=1;j<=7;j++){
                        scheduleCourseService.save(new ScheduleCourse(scheduleId,j,i));
                    }
                }
        }
        if(timeService.remove(new LambdaQueryWrapper<TimeTable>().eq(TimeTable::getScheduleId,scheduleId))){
            timeService.saveBatch(timeTables);
            scheduleService.update(new LambdaUpdateWrapper<Schedule>().eq(Schedule::getId,scheduleId).set(Schedule::getPitchNum,timeTables.size()));
            return R.success("修改成功");
        }else{
            return R.err("修改失败，稍后再试");
        }
    }

    @RequestRoles({"student"})
    @GetMapping("/selfSchedule")
    @ApiOperation("a获取自身当前课程表详细信息(查看当前在使用的课表)")
    public R<ReturnSchedule> selfSchedule(){
        Integer scheduleId = scheduleService.getIdByUserId((Integer) request.getSession().getAttribute("id"));
        if(scheduleId==null){
            return R.err("当前用户未设置当前课程表");
        }
        return getSchedule(scheduleId);
    }
    @RequestRoles({"student","teacher"})
    @GetMapping("/getSchedule")
    @ApiOperation("a获取课程表详细信息(用于查看其他课程表)")
    public R<ReturnSchedule> getSchedule(
        @ApiParam("课表id")@RequestParam("scheduleId") Integer scheduleId
    ){
        Schedule schedule = scheduleService.getById(scheduleId);
        if(schedule==null){
            return R.err("课表id有误");
        }
        //课程表未公开 并且创建者不是请求者
        if(schedule.getIsPublic()==0&&schedule.getUserId()!=request.getSession().getAttribute("id")){
            return R.err("无权限获取");
        }
        Integer culWeekly = AESUtil.getCulWeekly(schedule.getStartDate(),schedule.getWeekly(),schedule.getState());
        ReturnSchedule Returnschedule = new ReturnSchedule(
                scheduleId,
                schedule.getName(),
                culWeekly,
                userService.getNameById(schedule.getUserId()),
                timeService.list(new LambdaQueryWrapper<TimeTable>().eq(TimeTable::getScheduleId,scheduleId)),
                setCourseDate(culWeekly,scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,1))),
                setCourseDate(culWeekly,scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,2))),
                setCourseDate(culWeekly,scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,3))),
                setCourseDate(culWeekly,scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,4))),
                setCourseDate(culWeekly,scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,5))),
                setCourseDate(culWeekly,scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,6))),
                setCourseDate(culWeekly,scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,7)))
        );
        return R.success(Returnschedule);
    }
    @RequestRoles({"student","teacher"})
    @GetMapping("/getScheduleWith")
    @ApiOperation("a获取课程表详细信息(课程表市场)")
    public R<ReturnSchedule> getScheduleWith(
            @ApiParam("课表id")@RequestParam("scheduleId") Integer scheduleId
    ){
        Schedule schedule = scheduleService.getById(scheduleId);
        if(schedule==null){
            return R.err("课表id有误");
        }
        //课程表未公开 并且创建者不是请求者
        if(schedule.getIsPublic()==0&&schedule.getUserId()!=request.getSession().getAttribute("id")){
            return R.err("无权限获取");
        }
        Integer culWeekly = AESUtil.getCulWeekly(schedule.getStartDate(),schedule.getWeekly(),schedule.getState());
        ReturnSchedule Returnschedule = new ReturnSchedule(
                scheduleId,
                schedule.getName(),
                culWeekly,
                userService.getNameById(schedule.getUserId()),
                timeService.list(new LambdaQueryWrapper<TimeTable>().eq(TimeTable::getScheduleId,scheduleId)),
                setCourseDate1(scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,1))),
                setCourseDate1(scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,2))),
                setCourseDate1(scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,3))),
                setCourseDate1(scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,4))),
                setCourseDate1(scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,5))),
                setCourseDate1(scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,6))),
                setCourseDate1(scheduleCourseService.list(new LambdaQueryWrapper<ScheduleCourse>().eq(ScheduleCourse::getScheduleId,scheduleId).eq(ScheduleCourse::getIndexWeek,7)))
        );
        return R.success(Returnschedule);
    }

    @RequestRoles({"student","teacher"})
    @DeleteMapping("/delSchCourse")
    @ApiOperation("c删除课程表中的课程")
    public R<String> delSchCourse(
        @ApiParam("课表中的课程位置id")@RequestParam("scheduleCourseId") Integer scheduleCourseId
    ){
        scheduleCourseService.update(new LambdaUpdateWrapper<ScheduleCourse>().eq(ScheduleCourse::getId,scheduleCourseId)
                .set(ScheduleCourse::getState,0)
                .set(ScheduleCourse::getCourseId,0));
        return R.success("删除成功");
    }

    public List<ScheduleCourse> setCourseDate1(List<ScheduleCourse> list){
        for (ScheduleCourse scheduleCourse : list) {
                Course course = courseService.getById(scheduleCourse.getCourseId());
                if(course==null){
                    scheduleCourse.setState(0);
                    scheduleCourse.setCourseId(0);
                }else{
                    scheduleCourse.setCourseName(course.getCourseName());scheduleCourse.setCourseTeacherName(courseService.getTeacherNameByCourseId(scheduleCourse.getCourseId()));
                }
        }
        return list;
    }
    public List<ScheduleCourse> setCourseDate(Integer culWeek,List<ScheduleCourse> list){
        for (ScheduleCourse scheduleCourse : list) {
            if(scheduleCourse.getState()==1){//进行是否在 周次中存在课程
                Course course = courseService.getById(scheduleCourse.getCourseId());
                if(course==null){
                    scheduleCourse.setState(0);
                    scheduleCourse.setCourseId(0);
                }else{
                    if(culWeek>=scheduleCourse.getStartWeekly()&&culWeek<=scheduleCourse.getEndWeekly()){
                        if(scheduleCourse.getSkip()==3){//全周都有该课
                            scheduleCourse.setState(1);
                        }else{
                            if(scheduleCourse.getSkip()==2){
                                scheduleCourse.setSkip(0);
                            }
                            if(culWeek%2==scheduleCourse.getSkip()){//判断单双周
                                scheduleCourse.setState(1);
                            }else {
                                scheduleCourse.setState(2);
                            }
                        }
                    }else{
                        //不满足单双周或不在本周内，则为非本周课程
                        scheduleCourse.setState(2);
                    }
                    scheduleCourse.setCourseName(course.getCourseName());
                    scheduleCourse.setCourseTeacherName(courseService.getTeacherNameByCourseId(scheduleCourse.getCourseId()));

                }
            }
        }
        return list;
    }

}
